#Python library imports
import re
#External libraries imports
from pyparsing import *
#Internal imports
from FSPNamespace import FSPNamespace
from FSPSymbolParser import FSPSymbol
from ParsingUtilities import strJoin, uppercaseRegex, lowercaseRegex, UppercaseIdentifier, LowercaseIdentifier

variableRegex = re.compile(".*\{.*\}.*")

def _chain(ex, op, act):
  parser = ex + ZeroOrMore(Or([(Literal(o) + ex) for o in op]))
  return parser.setParseAction(act) if act else parser
def _tree(p):
  return p[0] if len(p) == 1 else _chain(_tree(p[1:]), p[0][0], p[0][1])
def _andOrImplementation(x, operation):
  for term in x:
    if re.match(variableRegex, term): return strJoin(x)
  x = [eval(i) for i in [j for j in x if j != "&&" and j != "||"]]
  if len(x) == 1: return str(int(x[0]))
  return str(int(any(x) if operation == "or" else all(x)))

class ExpressionParser(ParserElement):
  def __init__(self, namespace=None, justCheck=False):
    super(ExpressionParser, self).__init__()
    if not justCheck:
      if namespace: self._namespace = namespace
      else: self._namespace = FSPNamespace()
    self._expression = Forward()
    self._integer = Word(nums)
    self._variableId = LowercaseIdentifier.copy()
    if not justCheck: self._variableId.setParseAction(lambda x: "{" + x[0] + "}")
    self._templateParameter = (Literal("{") + LowercaseIdentifier + Literal("}")
      if justCheck else NoMatch())
    self._constantId = UppercaseIdentifier.copy() if justCheck else FSPSymbol(uppercaseRegex, "const", self._namespace)
    self._constantId.setParseAction(lambda x: x if justCheck else str(x[0]))
    self._atom = (self._integer ^ self._constantId ^ self._variableId ^ self._templateParameter ^
      (Literal("(") + self._expression + Literal(")")).setParseAction((lambda x: x) if justCheck else strJoin))
    self._factor = (((Optional(Literal("+")) ^ Literal("-")) + self._atom) ^
                   (Literal("!") + self._atom).setParseAction(
                      lambda u: u if justCheck or re.match(variableRegex, u[1])
                                  else str(int(not eval(u[1])))))
    self._expression << _tree(
      [[["||"], None if justCheck else lambda x: _andOrImplementation(x, "or")],
       [["&&"], None if justCheck else lambda x: _andOrImplementation(x, "and")],
       [["|"], None if justCheck else strJoin], [["^"], None], [["&"], None],
       [["==", "!="], None], [["<", "<=", ">", ">="], None],
       [["<<", ">>"], None], [["+", "-"], None],
       [["*", "/", "%"], None], self._factor])
  def parseImpl(self, instring, loc, doActions=True):
    return self._expression.parseImpl(instring, loc, doActions)

"""
LA SEGUENTE VERSIONE FA EXPRESSION EVALUATION
#Python library imports
import re
#External libraries imports
from pyparsing import *
#Internal imports
from FSPSymbolParser import FSPSymbol
from ParsingUtilities import strJoin, uppercaseRegex, lowercaseRegex

variableRegex = re.compile(".*\{.*\}.*")

def _chain(ex, op, act):
  parser = ex + ZeroOrMore(Or([(Literal(o) + ex) for o in op]))
  return parser.setParseAction(act) if act else parser
def _tree(p):
  return p[0] if len(p) == 1 else _chain(_tree(p[1:]), p[0][0], p[0][1])
def _andOrImplementation(x, operation):
  for term in x:
    if re.match(variableRegex, term): return strJoin(x)
  x = [eval(i) for i in [j for j in x if j != "&&" and j != "||"]]
  if len(x) == 1: return str(int(x[0]))
  return str(int(any(x) if operation == "or" else all(x)))

class ExpressionParser(ParserElement):
  def __init__(self, namespace):
    super(ExpressionParser, self).__init__()
    self._namespace = namespace
    self._expression = Forward()
    self._integer = Word(nums)
    self._variableId = Regex(lowercaseRegex)
    self._variableId.setParseAction(lambda x: "{" + x[0] + "}")
    self._constantId = FSPSymbol(uppercaseRegex, "const", self._namespace)
    self._constantId.setParseAction(lambda x: str(x[0]))
    self._atom = (self._integer ^ self._constantId ^ self._variableId ^
      (Literal("(") + self._expression + Literal(")")).setParseAction(strJoin))
    self._factor = (((Optional(Literal("+")) ^ Literal("-")) + self._atom) ^
                   (Literal("!") + self._atom).setParseAction(
                      lambda u: u if re.match(variableRegex, u[1])
                                  else str(int(not eval(u[1])))))
    self._expression << _tree(
      [[["||"], lambda x: _andOrImplementation(x, "or")],
       [["&&"], lambda x: _andOrImplementation(x, "and")],
       [["|"], strJoin], [["^"], None], [["&"], None],
       [["==", "!="], None], [["<", "<=", ">", ">="], None],
       [["<<", ">>"], None], [["+", "-"], None],
       [["*", "/", "%"], None], self._factor])
  def parseImpl(self, instring, loc, doActions=True):
    return self._expression.parseImpl(instring, loc, doActions)
"""
